home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 3
/
Gold Medal Software - Volume 3 (Gold Medal) (1994).iso
/
prog
/
96cqa.exe
/
VARRAY.CPP
< prev
Wrap
C/C++ Source or Header
|
1994-06-01
|
6KB
|
222 lines
////////////////////////////////////////////////////////////////
// VARRAY.CPP
// This program shows how to implement a dynamic array of objects
// that can be resized in place. To compile:
//
// bcc varray.cpp (Borland)
// cl varray.cpp (Microsoft)
// sc varray.cpp (Symantec)
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <memory.h>
#define TRACE printf // For diagnostics
//////////////////
// Overloaded operator new operator lets you construct
// an object at any location in memory.
//
void* operator new (size_t, void* p) { return p; }
//////////////////
// Some class that has a constructor and copy constructor
//
class Foo {
static int nextID; // next unique Foo ID
int id; // this object's ID
char s[12]; // filler to make sizeof(Foo)=16;
public:
Foo(); // normal no-arg constructor
Foo(const Foo& obj); // copy constructor
virtual ~Foo();
int GetID() { return id; }
};
int Foo::nextID = 0; // instantiate
// Default constructor: set ID and display diagnostic
Foo::Foo()
{
id = ++nextID;
TRACE("(constructing Foo %2d at %p)\n", id, this);
}
// Copy constructor: copy ID and display diagnostic
Foo::Foo(const Foo& obj)
{
id = obj.id;
TRACE("(copied Foo from %p to %p)\n", &obj, this);
}
// Destructor: display diagnostic
Foo::~Foo()
{
TRACE("(destroying Foo %2d at %p)\n", id, this);
}
//////////////////
// Dynamic array class
//
class Array {
Foo* m_pObj; // array of Foo objects
int m_nObj; // number of objects in array
void ConstructObjs(Foo* pObj, int n);
void DestroyObjs (Foo* pObj, int n);
public:
Array(int nObj);
~Array();
Foo& operator[] (int i)
{ assert(0<=i && i<m_nObj); return m_pObj[i]; }
int Size()
{ return m_nObj; }
int ReSize(int nObj);
};
//////////////////
// Create array of nObj objects
//
Array::Array(int nObj)
{
m_pObj = (Foo*)malloc(nObj * sizeof(Foo));
m_nObj = nObj;
TRACE("Array::Array: allocated %d objects at %p\n", m_nObj, m_pObj);
ConstructObjs(m_pObj, nObj);
}
//////////////////
// Re-size array
//
int Array::ReSize(int nObj)
{
assert(m_pObj);
if (nObj < m_nObj) {
// Shrinking array: destroy dead objects
TRACE("Array::ReSize: shrinking array to %d objects\n", nObj);
DestroyObjs(&m_pObj[nObj], m_nObj-nObj);
} else if (nObj > m_nObj) {
// Array is growing:
// First see if could realloc in same buffer.
//
// This is where knowledge of the memory manager is required:
// For MSC, true size of block (in small/medium model) is the
// word preceeding the block's address; for Borland, it's the
// word before that.
//
Foo *pNewObj;
#ifdef __BORLANDC__
int sizeIHave = *( ((unsigned*)m_pObj)-2 );
#else
int sizeIHave = *( ((unsigned*)m_pObj)-1 );
#endif
// Do sanity-check on size
assert(sizeIHave >= m_nObj*sizeof(Foo));
int sizeIWant = nObj * sizeof(Foo);
if (sizeIHave>=sizeIWant) {
// Block is big enough to grow in place: do the realloc
//
TRACE("Array::ReSize: growing array in place to %d objects\n",nObj);
pNewObj = (Foo*)realloc(m_pObj, sizeIWant);
assert(pNewObj==m_pObj);
} else {
// realloc would have to allocate new memory anyway, so do
// it myself. Don't call realloc because I need both arrays
// in place at the same time so I can copy old==>new
//
pNewObj = (Foo*)malloc(sizeIWant);
if (pNewObj==NULL)
return 0; // failed
TRACE("Array::ReSize: allocating new array of %d objects at %p\n",
nObj, pNewObj);
// Copy and destroy the old objects
// Must do memcpy first to copy address of vtable!
memcpy(pNewObj, m_pObj, m_nObj*sizeof(Foo));
for (int i=0; i<m_nObj; i++)
new (&pNewObj[i]) Foo(m_pObj[i]);
DestroyObjs(m_pObj, m_nObj);
// Free the old array
TRACE("Array::ReSize: freeing old memory at %p\n", m_pObj);
free(m_pObj);
m_pObj = pNewObj; // my new array now
}
// Construct the extra new objects
ConstructObjs(&pNewObj[m_nObj], nObj-m_nObj);
}
m_nObj = nObj;
return 1; // success
}
//////////////////
// Construct n objects at a given address in memory
//
void Array::ConstructObjs(Foo* pObj, int n)
{
for (int i=0; i<n; i++)
new (&pObj[i]) Foo; // call overloaded new operator
}
//////////////////
// Destroy n objects at a given address in memory
//
void Array::DestroyObjs(Foo* pObj, int n)
{
for (int i=0; i<n; i++)
pObj[i].Foo::~Foo(); // call destructor explicitly
}
//////////////////
// Destroy array: destroy each object, then free their memory
//
Array::~Array()
{
DestroyObjs(m_pObj, m_nObj);
TRACE("Array::~Array: destroying memory at %p\n", m_pObj);
free(m_pObj);
m_pObj = NULL; // safe
m_nObj = 0;
}
//////////////////
// Print contents of array
//
static void PrintArray(Array *pArray)
{
printf("\nHere's the Array\n================\n");
for (int i=0; i<pArray->Size(); i++) {
Foo& obj = (*pArray)[i];
printf("Object %2d at %p\n", obj.GetID(), &obj);
}
printf("\n");
}
//////////////////
// Array test program: create an array and resize it
//
int main(int, char**)
{
Array* pArray = new Array(5);
PrintArray(pArray);
static int NEWSIZE[3] = { 10, 7, 9 };
for (int i=0; i<3; i++) {
pArray->ReSize(NEWSIZE[i]);
PrintArray(pArray);
}
printf("Goodbye!\n\n");
delete pArray;
return 0;
}